package coap.network;

import coap.messages.Message;

import java.util.*;

/**
 * Created by IntelliJ IDEA.
 * User: iodine
 * Date: Jan 21, 2012
 * Time: 4:58:44 PM
 * To change this template use File | Settings | File Templates.
 */
public class TimeoutChecker extends Thread {

    private TreeMap<Long, HashSet<Message>> outstandingMessages = new TreeMap<Long, HashSet<Message>>();
    private TimeoutHandler handler = null;
    private boolean running = true;

    public TimeoutChecker(TimeoutHandler handler) {
        this.handler = handler;
    }

    public void terminate() {
        this.running = false;
    }

    public synchronized void add(Message message) {
        System.out.println("add " + message.getMessageID() + " to checker");
        long timeoutTime = message.getNextTimeoutTime();
        if (!this.outstandingMessages.containsKey(timeoutTime))
            this.outstandingMessages.put(timeoutTime, new HashSet<Message>());
        this.outstandingMessages.get(timeoutTime).add(message);
    }

    public synchronized void checkTimeout() {
        Iterator<Map.Entry<Long, HashSet<Message>>> iter = this.outstandingMessages.entrySet().iterator();
        LinkedList<Message> tmp = new LinkedList<Message>();
        while (iter.hasNext()) {
            Map.Entry<Long, HashSet<Message>> item = iter.next();
            if (item.getKey() <= System.currentTimeMillis()) {
                for (Message msg : item.getValue()) {
                    boolean overLimit = !msg.timeout();
                    if (overLimit)
                        handler.timeout(msg, true);
                    else {
                        handler.timeout(msg, false);
                        tmp.add(msg);
                    }
                }
                iter.remove();
            } else
                break;
        }
        for(Message m : tmp)
            this.add(m);
    }

    public synchronized void remove(Message message) {
        if (outstandingMessages.containsKey(message.getNextTimeoutTime())) {
            this.outstandingMessages.get(message.getNextTimeoutTime()).remove(message);
            System.out.println("remove "+message.getMessageID()+" from checker");
            if(this.outstandingMessages.get(message.getNextTimeoutTime()).size()==0)
                this.outstandingMessages.remove(message.getNextTimeoutTime());
        }
    }

    public void run() {
        while (running) {
            long sleepTime = 1000;
            synchronized (this) {
                if (this.outstandingMessages.size() > 0) {
                    sleepTime = this.outstandingMessages.firstKey() - System.currentTimeMillis();
                }
            }
            try {
                if (sleepTime > 0)
                    Thread.sleep(sleepTime);
            } catch (InterruptedException e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            }
            this.checkTimeout();

        }
    }


}
